package com.coffee.middleware.dict.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.coffee.core.CoffeeException;
import com.coffee.core.CoffeeResponseEnum;
import com.coffee.middleware.dict.entity.DictDataDTO;
import com.coffee.middleware.dict.entity.DictDataEntity;
import com.coffee.middleware.dict.entity.DictTypeEntity;
import com.coffee.middleware.dict.repository.DictDataRepository;
import com.coffee.middleware.dict.repository.DictTypeRepository;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author songkui
 * @since 2024/5/16 9:36
 */
@Service
@Slf4j
@AllArgsConstructor
public class CoffeeDictRedisServiceImpl implements CoffeeDictRedisService {

    public static final String COFFEE_DICT = "COFFEE:DICT";

    private final DictDataRepository dictDataRepository;
    private final DictTypeRepository dictTypeRepository;
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public List<DictDataDTO> listByTypeCode(String typeCode) {
        return (List<DictDataDTO>) redisTemplate.opsForHash().get(COFFEE_DICT, typeCode);
    }

    @Override
    public Map<String, List<DictDataDTO>> mapByAll() {
        Set<Object> keys = redisTemplate.opsForHash().keys(COFFEE_DICT);
        if (CollectionUtil.isEmpty(keys)){
            return null;
        }

        Map<String, List<DictDataDTO>> map = MapUtil.newHashMap(keys.size());
        for (Object key : keys){
            map.put((String) key, (List<DictDataDTO>) redisTemplate.opsForHash().get(COFFEE_DICT, key));
        }
        return map;
    }


    public Map<String, String> mapDictByCode(String typeCOde){
        List<DictDataDTO> list = listByTypeCode(typeCOde);
        if (CollectionUtil.isEmpty(list)){
            return null;
        }
        return list.stream().collect(Collectors.toMap(d -> String.valueOf(d.getDictCode()), DictDataDTO::getDictName));
    }


    //---------refresh------------------------
    public void refreshByTypeId(Integer typeId) {
        DictTypeEntity typeEntity = dictTypeRepository.getById(typeId);
        if (null == typeEntity) {
            throw new CoffeeException(CoffeeResponseEnum.NotData);
        }
        List<DictDataDTO> list = listByTypeId(typeId);
        if (CollectionUtil.isEmpty(list)) {
            redisTemplate.opsForHash().delete(COFFEE_DICT, typeEntity.getTypeCode());
        } else {
            redisTemplate.opsForHash().put(COFFEE_DICT, typeEntity.getTypeCode(), list);
        }

    }


    public synchronized void refreshAll() {
        List<DictTypeEntity> typeList = dictTypeRepository.list();
        Map<Integer, List<DictDataDTO>> dataMap = listAll();
        if (CollectionUtil.isEmpty(typeList) || CollectionUtil.isEmpty(dataMap)) {
            throw new CoffeeException(CoffeeResponseEnum.NotData);
        }

        for (DictTypeEntity typeEntity : typeList) {
            List<DictDataDTO> dictDataList = dataMap.get(typeEntity.getId());
            if (CollectionUtil.isEmpty(dictDataList)) {
                redisTemplate.opsForHash().delete(COFFEE_DICT, typeEntity.getTypeCode());
            } else {
                redisTemplate.opsForHash().put(COFFEE_DICT, typeEntity.getTypeCode(), dictDataList);
            }
        }

        log.info("Refresh all data dict to redis success");

    }

    private List<DictDataDTO> listByTypeId(Integer typId) {
        List<DictDataEntity> list = dictDataRepository.listByType(typId);
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }
        return list.stream().map(DictDataEntity::buildDTO).collect(Collectors.toList());
    }

    private Map<Integer, List<DictDataDTO>> listAll() {
        List<DictDataEntity> list = dictDataRepository.list();
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }
        return list.stream().collect(Collectors.groupingBy(DictDataEntity::getTypeId,
                Collectors.mapping(DictDataEntity::buildDTO, Collectors.toList())));
    }





}
